#include <iostream>

#include "Liste.h"

using namespace std;


//Initialisattion de la liste
Liste::Liste() : m_premier(0), nbr_element(0) {}

Liste::~Liste(){while(m_premier != 0) supprimerEnTete();}


//Suppression de la liste ou d'une cellule
void Liste::supprimerEnTete(){

    if(m_premier != 0){
        Noeud* c = m_premier;
        m_premier = c->GetNoeudSuivant();
        delete c;

        nbr_element--;
    }
}

void Liste::supprimerEnQueue()
{
    Noeud* tempo = m_premier;

    if((m_premier != 0) & (tempo->GetNoeudSuivant() != 0)){

        while(tempo->GetNoeudSuivant()->GetNoeudSuivant() != 0){tempo = tempo->GetNoeudSuivant();}

        delete tempo->GetNoeudSuivant()->GetAdresseElement();
        delete tempo->GetNoeudSuivant();
        tempo->SetNoeudSuivant(0);

        nbr_element--;
    }
}


    ////////////////////////////////////////////////////////////
    // Méthodes d'ajout dans la liste
    ////////////////////////////////////////////////////////////

//Chainage en Tete
void Liste::ajoutEnTete(const Elem nouvElement,const int stockage){

    m_premier = new Noeud(nouvElement, m_premier, stockage); //m_premier peut etre vide ou contenir une adresse

    nbr_element++;
}


//Chainage en Queue
void Liste::ajoutEnQueue(const Elem nouvElement,const int stockage){

    if(m_premier == 0)
    ajoutEnTete(nouvElement,stockage);
    else ajoutEnQueueConnaissantNoeud(nouvElement,stockage);
}

    ////////////////////////////////////////////////////////////
    // Méthodes internes (static) utilisées par les méthodes d'ajouts
    ////////////////////////////////////////////////////////////

void Liste::ajoutEnQueueConnaissantNoeud(const Elem nouvElement,const int stockage){

    Noeud* c = m_premier;

    //recherche du dernier Noeud
    while(c->GetNoeudSuivant() != 0){c = c->GetNoeudSuivant();}

    c->SetNoeudSuivant(new Noeud(nouvElement,0,stockage));

    nbr_element++;

}


//Ajouter une cellule apres une autre dans la liste
void Liste::ajouterApresNoeud(Noeud* c, const Elem nouvElement,const int stockage){

    if(c->GetNoeudSuivant() != 0)
    {ajouterNoeud(c,nouvElement,stockage);}
    else {ajoutEnQueue(nouvElement,stockage);}

}

void Liste::ajouterNoeud(Noeud* c, const Elem nouvElement,const int stockage){
        c->SetNoeudSuivant(new Noeud(nouvElement,c->GetNoeudSuivant(),stockage));
        nbr_element++;
}

void Liste::supprimerNoeud(Noeud* c)
{
    //si c'est la cellule en tête
    if(c == m_premier)
    supprimerEnTete();

    else
    {
        //si la cellule est en queue le neoud suivant sera null
        Noeud* Precedent = GetNoeudPrecedent(c);
        Precedent->SetNoeudSuivant(c->GetNoeudSuivant());
        delete c;
    }
}


Noeud* Liste::GetNoeudPrecedent(Noeud* c)
{
    Noeud* tempo = m_premier;
    while (tempo->GetNoeudSuivant() != c)
    {
        tempo = c->GetNoeudSuivant();
    }
    return tempo;
}


    ////////////////////////////////////////////////////////////
    // Accesseurs simples
    ////////////////////////////////////////////////////////////

//Accesseurs de base
Elem Liste::GetPremierElement() const{
    return m_premier->GetAdresseElement();
}

unsigned int Liste::GetNbrElements() const{
    return nbr_element;
}

Noeud* Liste::GetNoeudEnTete(){
    return m_premier;
}

Noeud* Liste::GetNoeudSuivant(Noeud* c){
    return c->GetNoeudSuivant();
}

//Accesseur de recherche
Noeud* Liste::GetNoeudDeElement(const Elem ElementCherche){

    Noeud* c = m_premier;

    while (c != 0){
        if(c->GetAdresseElement() == ElementCherche) return  c; else c = c->GetNoeudSuivant();
    }

    return 0;
}
